前一章中的元组将一些类型列表的值聚合为单个类值，使它们具有与简单结构体相同的功能。这自然就会想知道，联合的对应类型是什么:其将包含单个值，但该值将具有从一些可能类型中选择的类型。例如，一个数据库字段可能包含一个整数、浮点值、字符串或二进制对象，但在相应的时间内，其只能表示这些类型中的一种。

本章中，我们开发了一个类模板Variant，可以动态存储给定的一组值类型中的一个值，类似于C++17标准库的std::variant<>。Variant是可辨识联合，从而其值的类型是动态的，并提供了比C++联合更好的类型安全性。Variant本身是一个可变参数模板，可接受动态值可能具有的类型列表。

\begin{lstlisting}[style=styleCXX]
Variant<int, double, string> field;
\end{lstlisting}

可以存储整型、双精度或字符串，但只能存储其中一个值。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}类型列表在声明Variant时是固定的，所以Variant是封闭的可辨识联合。开放的可辨识联合允许在创建时不知道有哪些类型的值存储在联合中。第22章中讨论的FunctionPtr类可以看作是一种开放可识别联合。
\end{tcolorbox}

下面的程序演示了Variant的行为:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{variant/variant.cpp}
\begin{lstlisting}[style=styleCXX]
#include "variant.hpp"
#include <iostream>
#include <string>
 
int main()
{
	Variant<int, double, std::string> field(17);
	if (field.is<int>()) {
		std::cout << "Field stores the integer "
				<< field.get<int>() << ’\n’;
	}
	field = 42; // assign value of same type
	field = "hello"; // assign value of different type
	std::cout << "Field now stores the string ’"
			<< field.get<std::string>() << "’\n";
}
\end{lstlisting}

输出：

\begin{tcblisting}{commandshell={}}
Field stores the integer 17
Field now stores the string "hello"
\end{tcblisting}

可以赋值给Variant任何类型的值，可以使用成员函数is<T>()来测试Variant当前是否包含类型为T的值，然后使用成员函数get<T>()获取存储值。































